﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common;

namespace DataAccess
{
    public class SmartHouseInitializer
    {
        //I've thought such method will be also convenient
        public CommonDataStorage CreateDataStorage()
        {
            DataAccessor dataAccessor = new DataAccessor();
            SmartHouseDataSet dsSHouse = dataAccessor.Get();
            CommonDataStorage storage = CreateDataStorage(dsSHouse);
            return storage;
        }

        public CommonDataStorage CreateDataStorage(SmartHouseDataSet SHDataSet)
        {
            CommonDataStorage storage = new CommonDataStorage();
            storage.Variables = CreateVariables(SHDataSet.Variables);
            storage.Events = CreateEvents(SHDataSet, storage.Variables);
            storage.Operations = CreateOperations(SHDataSet, storage);
            storage.Bindings = CreateBindings(SHDataSet, storage);

            return storage;
        }

        protected List<Variable> CreateVariables(SmartHouseDataSet.VariablesDataTable variableTable)
        {
            List<Variable> variables = new List<Variable>(30);

            foreach (DataAccess.SmartHouseDataSet.VariablesRow row in variableTable.Rows)
            {
                Common.Variable variable = new Common.Variable(row.Name, row.Description, row.InitialValue, row.VariableId);

                variables.Add(new Client().ClientVariable(variable, row.VariableType));
            }

            return variables;
        }

        protected List<SmartHouseEvent> CreateEvents(SmartHouseDataSet SMDataSet, List<Variable> variables)
        {
            List<SmartHouseEvent> events = new List<SmartHouseEvent>(20);
            List<Variable> variablesInner = new List<Variable>(20);
            ConditionSet condSetInner = new ConditionSet();

            foreach (SmartHouseDataSet.EventsRow eventRow in SMDataSet.Events)
            {
                var variablesFromDB = SMDataSet.EventWithVariable.Where(evVariabl => evVariabl.EventId.Equals(eventRow.EventId));

                foreach (var variableFromDb in variablesFromDB)
                {
                    variablesInner.Add(variables.Where(v => v.Id.Equals(variableFromDb.VariableId)).FirstOrDefault());
                }

                var conditionsFromDB = SMDataSet.EventWithCondition.Where(evVariabl => evVariabl.EventId.Equals(eventRow.EventId));

                foreach (var conditionItem in conditionsFromDB)
                {
                    var currentCondition = SMDataSet.Conditions.Where(cond => cond.ConditionId.Equals(conditionItem.ConditionId)).FirstOrDefault();

                    Variable variabl = variables.Where(v => v.Id.Equals(currentCondition.VariableId)).FirstOrDefault();
                    ConditionType currCondType = (ConditionType)Enum.Parse(typeof(ConditionType), currentCondition.conditionType, true);
                    condSetInner.ListOfConditions.Add(new Condition(variabl, currentCondition.ROperand, currCondType));
                }

                events.Add(new SmartHouseEvent(eventRow.Name, eventRow.Description, variablesInner, condSetInner, eventRow.isActive));
            }

            /*var evWithVariables = from ev in SMDataSet.EventWithVariable
                                  group ev by ev.EventId into g
                                  join evV in SMDataSet.Events on g.Key equals evV.EventId
                                  select new
                                  {
                                      evV.EventId,
                                      evV.Name,
                                      evV.Description,
                                      evV.isActive,
                                      variables = from v in g
                                                  join variabl in SMDataSet.Variables on v.VariableId equals variabl.VariableId
                                                  select new {  variabl.Name, 
                                                                variabl.Description, 
                                                                variabl.InitialValue, 
                                                                variabl.VariableType },
                                  };

            var ConditionsResult = from ev in SMDataSet.EventWithCondition
                                   group ev by ev.EventId into g
                                   select new
                                   {
                                       eventId = g.Key,
                                       conditions = from c in g
                                                    join cond in SMDataSet.Conditions on c.ConditionId equals cond.ConditionId
                                                    select new
                                                    {
                                                        variable = from v in SMDataSet.Variables
                                                                   where v.VariableId == cond.VariableId
                                                                   select new { v.Name, v.Description, v.InitialValue, v.VariableType },
                                                        cond.conditionType,
                                                        cond.ROperand
                                                    }
                                   };

            int EventIndex = -1;
            foreach (var eventItem in evWithVariables)
            {
                EventIndex++;
                List<Variable> currentVariables = new List<Variable>(10);

                foreach (var variableItem in eventItem.variables)
                {
                    Variable variabl = variables.Where(v => v.Name.Equals(variableItem.Name)).Select(v => v).FirstOrDefault();
                    currentVariables.Add(variabl);
                }

                var conditions = ConditionsResult.Where(e => e.eventId.Equals(eventItem.EventId)).Select(e => e.conditions);
                ConditionSet condSet = new ConditionSet();

                foreach (var conditionItem in conditions)
                {
                    Variable variabl = variables.Where(v => v.Name.Equals(conditionItem.ElementAt(0).variable.ElementAt(0).Name)).Select(v => v).FirstOrDefault();
                    ConditionType currCondType = (ConditionType)Enum.Parse(typeof(ConditionType), conditionItem.ElementAt(0).conditionType, true);
                    condSet.ListOfConditions.Add(new Condition(variabl, conditionItem.ElementAt(0).ROperand, currCondType));
                }

                events.Add(new SmartHouseEvent(eventItem.Name, eventItem.Description, currentVariables, condSet, eventItem.isActive));
            }*/


            return events;
        }

        protected List<Operation> CreateOperations(SmartHouseDataSet SMDSet, CommonDataStorage CDS)
        {
            List<Operation> operations = new List<Operation>(10);

            var operationWithAction = from op in SMDSet.OperationWithAction
                                      group op by op.OperationId into g
                                      join opP in SMDSet.Operations on g.Key equals opP.OperationId
                                      select new
                                      {
                                          opP.Name,
                                          opP.Description,
                                          opP.isActive,
                                          actions = from a in g
                                                    join aa in SMDSet.Action on a.ActionId equals aa.ActionId
                                                    select new { aa.ActionType, aa.ActionData }
                                      };
            foreach (var operationItem in operationWithAction)
            {
                LinkedList<Common.Action> actions = new LinkedList<Common.Action>();

                foreach (var actionItem in operationItem.actions)
                {
                    switch (actionItem.ActionType)
                    {
                        case "set": actions.AddLast(ParseToSetAction(actionItem.ActionData, CDS.Variables)); break;
                        case "send": actions.AddLast(ParseToSendAction(actionItem.ActionData)); break;

                        default: //return null;// it's not null, but some kind of problem
                            throw new NotImplementedException();
                    }
                }
                // some difficult moment was resolved here
                Operation operationToReturn = new Operation(operationItem.Name, operationItem.Description, operationItem.isActive);
                operationToReturn.ActionSet = actions;
                operations.Add(operationToReturn);
            }

            return operations;
        }
      
        protected List<Binding> CreateBindings(SmartHouseDataSet SHDSet, CommonDataStorage CDS)
        {
            List<Binding> bindings = new List<Binding>(10);

            var bindingResult = from b in SHDSet.Bindings
                                join ev in SHDSet.Events on b.EventId equals ev.EventId
                                join op in SHDSet.Operations on b.OperationId equals op.OperationId
                                select new
                                {
                                    b.isActive,
                                    EventName = ev.Name,
                                    OperationName = op.Name
                                };
            foreach (var bindingItem in bindingResult)
            {
                SmartHouseEvent ev = CDS.Events.Where(evV => evV.Name.Equals(bindingItem.EventName)).Select(evV => evV).FirstOrDefault();
                Operation operat = CDS.Operations.Where(oper => oper.Name.Equals(bindingItem.OperationName)).Select(oper => oper).FirstOrDefault();

                /*bindings.Add(new Binding
                {
                    IsActive = bindingItem.isActive,
                    TargetEvent = ev,
                    TargetOperation = operat
                });*/
                Binding b = new Binding(ev, operat);
                b.IsActive = bindingItem.isActive;
                bindings.Add(b);
            }

            return bindings;
        }

        protected SetCommand ParseToSetAction(string actionData, List<Variable> variables)
        {
            char ch = ' ';
            string[] itemsAction = actionData.Split(new[] { ch }, StringSplitOptions.None);
            Variable variabl = variables.Where(v => v.Name.Equals(itemsAction[0])).FirstOrDefault();

            return new SetCommand(variabl, itemsAction[1]);
        }

        protected SendCommand ParseToSendAction(string actionData)
        {
            char ch = ' ';
            string[] itemsAction = actionData.Split(new[] { ch }, StringSplitOptions.None);

            return new SendCommand(itemsAction[0], itemsAction[1]);
        }

    }
}
